package weeny.util.io;

import java.awt.event.ActionEvent;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.swing.JFileChooser;

import weeny.util.logs.Debug;

/**
 * This class provides some functions for file IO. 
 * 
 * @author weeny
 */

public class IOUtil {

	/**
	 * the system file separator. For example, in windows, it is slash (right to
	 * left). But in mac/linux, it should be back slash (left to right).
	 */
	public final static String SLASH;

	/**
	 * The default safe date format: Month_Date_Hour_Minute_Second, which can be
	 * used as ID, such as folder name, etc.
	 */	
	public final static SimpleDateFormat DATE_FORMAT;
	
	/**
	 * The regular expression to parse the {@link #DATE_FORMAT}
	 */
	public final static String DATE_REGEX;
	
	/**
	 * every excution only keeps *ONE* global default folder. It could be 
	 * "C:/javaDebug/<current_time>" or "~/Desktop/<current_time>" based on
	 * different OSs.
	 */
	private static final String OUTPUT_FOLDER;

	static {//initializing all the constants
		SLASH = System.getProperty("file.separator");
		DATE_FORMAT = new SimpleDateFormat("MM_dd_HH_mm_ss");
		DATE_REGEX = DATE_FORMAT.toPattern().replaceAll("[a-zA-Z]", "\\\\d");

		if (System.getProperties().get("os.name").toString().startsWith("Ma")) {
			//it is a mac
			OUTPUT_FOLDER = desktop()+timeString()+SLASH;
		}
		else {
			//by default, we assume the others are windows :)
			OUTPUT_FOLDER = "c:"+SLASH+"javaDebug"+SLASH+timeString()+SLASH;
		}
		//TODO should we consider linux platform?
	}

	public static boolean isMac(){
		return System.getProperties().get("os.name").toString().startsWith("Ma");
	}
	/**
	 * Generate a string representation of current time in the format of
	 * {@link #DATE_FORMAT}, Please notice that the smallest unit is *SECOND*.
	 * So if you call it twice within a second, you should probably get two
	 * identical strings -_-||
	 * 
	 * @return
	 */
	public static String timeString(){
		Date date = new Date(System.currentTimeMillis());
		return DATE_FORMAT.format(date);
	}
	
	/**
	 * Give the path to the user's destop folder
	 * @return
	 */
	public static String desktop(){
		return System.getProperty("user.home")+SLASH+"Desktop"+SLASH;
	}

	/**
	 * We find the default input folder in the global default directory,
	 * which is decided by {@link #OUTPUT_FOLDER}. 
	 * 
	 * Because it is the input, we try to find the newest folder having files,
	 * If we cannot find one (meaning all <time> folders are empty), just
	 * return the newest one.
	 * 
	 * @return the newest folder containing files for you to read from 
	 */
	public static String inputFolder(){
		File parent = new File(OUTPUT_FOLDER).getParentFile();
		List<String> inputs = FileUtil.subFoldersMatches(DATE_REGEX, parent);
		if (inputs.isEmpty()) {
			return outputFolder();
		}
		else{
			Collections.sort(inputs);
			for(int i = inputs.size()-1; i>=0; i--){
				if (new File(inputs.get(i)).list().length != 0) {
					return inputs.get(i);
				}
			}
			return inputs.get(inputs.size()-1);
		}
	}
	/**
	 * For each execution of the program, create a NEW folder, based on the time
	 * this class is accessed, i.e., {@link #OUTPUT_FOLDER} is initialized,
	 * create the folder if necessary
	 * 
	 * @return the folder path for output
	 */
	public static String outputFolder(){
		if (!new File(OUTPUT_FOLDER).exists()) {
			new File(OUTPUT_FOLDER).mkdirs();
		}
		return OUTPUT_FOLDER;
	}
	
	/**
	 * Based on the default path and mouse modifier to choose a target file,
	 * 1) if alt is done and dftFile is set, we just just return dftFile
	 * 2) otherwise, we open a filechooser with default path being:
	 *     i) if dftFile is set, the same path as the dftFile
	 *    ii) otherwise, the global default path decided by IOUtil, which is
	 *        usually C:/javaDebug/<current_time> or ~/Desktop/<current_time>
	 *        more details can be found in {@link #OUTPUT_FOLDER}
	 *        
	 * The return value chould be a solid String to indicate the file name or
	 * null indicating the filechooser has been canceled
	 * 
	 * @param e the actionevent to find out is alt key is down or not (We only
	 * use this piece of information, nothing else~)
	 * @param dft the default file path
	 * @param isOpen used to decide to show open dialog or save dialog 
	 * @return the chosen file, could be null if the file chooser is canceled
	 */
	public static String targetFile(ActionEvent e, String dft, boolean isOpen) {
		//if alt is not down or defaultFile is null, force to open file chooser
		if (!ModUtil.isAltDown(e) || dft == null) {
			JFileChooser chooser = null;
			String initialFolder = null;
			//now choosing the folder to open
			if (dft == null) {
				//if default file is not set, open the result folder
				initialFolder = isOpen? inputFolder(): outputFolder();
			}
			else{//otherwise open the folder having the default file
				initialFolder = new File(dft).getParentFile().getAbsolutePath();
			}
			//now we set the initial folder to save or load files
			chooser = new JFileChooser(initialFolder);
			
			int opt = JFileChooser.CANCEL_OPTION;
			//open the correct panel (load or save)
			if (isOpen){
				opt = chooser.showOpenDialog(null);
			}
			else{
				opt = chooser.showSaveDialog(null);
			}
			//return correct string
			if (opt == JFileChooser.APPROVE_OPTION){
				String target = chooser.getSelectedFile().getAbsolutePath();
				if (!target.contains(initialFolder)) {
					//you have changed the path to somewhere else, so we see if
					//we can delete the folder
					if (new File(OUTPUT_FOLDER).delete()) {
						Debug.info("Deleted: "+OUTPUT_FOLDER);
					}
				}
				return target;
			}
			else{
				Debug.info("FileChooser is canceled");
				//if (dftFile == null && !isLoad) 
				{
					//if is canceled, check if we need to delete the the folder
					if (new File(OUTPUT_FOLDER).delete()) {
						Debug.info("Deleted: "+OUTPUT_FOLDER);
					}
				}
				return null;
			}
		}
		else {
			return dft;
		}
	}
}